package mdb

import (
	"gitee.com/dennis-mxx/mxx-core-v2/mmodel"
	"strings"
	"xorm.io/builder"
	"xorm.io/xorm"
)

type pageable[T any] struct {
	entity    T
	page      mmodel.CmdPage
	engine    *xorm.Session
	condition any
	convert   func(field string) string
	cols      []string
}

func StartPage[T any](entity T, engine *xorm.Session, cmd mmodel.CmdPage) *pageable[T] {
	return &pageable[T]{page: cmd, engine: engine, entity: entity, convert: func(field string) string {
		return field
	}}
}
func (ew *pageable[T]) Sorter(fn func(field string) string) *pageable[T] {
	ew.convert = fn
	return ew
}

func (ew *pageable[T]) Where(condition any) *pageable[T] {
	ew.condition = condition
	return ew
}
func (ew *pageable[T]) Cols(cols []string) *pageable[T] {
	ew.cols = cols
	return ew
}

func (ew *pageable[T]) Find(beanList []T) (*mmodel.Pageable, error) {
	if ew.condition == nil {
		ew.condition = builder.Builder{}
	}
	if count, err := ew.engine.Where(ew.condition).Count(ew.entity); err == nil {

		int64Page := ew.page.GetPage()
		int64Size := ew.page.GetSize()
		remainder := count % int64Size
		maxPage := count / int64Size
		if remainder > 0 {
			maxPage += 1
		}
		result := &mmodel.Pageable{
			Page:          int64Page,
			Size:          int64Size,
			MaxPage:       maxPage,
			TotalElements: count,
		}
		if int64Page == 1 {
			result.First = true
		}
		if int64Page >= maxPage {
			result.Last = true
		}

		if int64Page > maxPage {
			result.CurrentElement = 0
			return result, nil
		} else {
			offset := (int64Page - 1) * int64Size
			ses := ew.engine.Where(ew.condition).Limit(int(int64Size), int(offset))
			for i := range ew.page.Sorter {
				arr := strings.Split(ew.page.Sorter[i], ",")
				if len(arr) == 2 {
					if strings.EqualFold("desc", arr[0]) {
						ses.Desc(ew.convert(arr[1]))
					} else {
						ses.Asc(ew.convert(arr[1]))
					}
				}
			}
			if len(ew.cols) > 0 {
				ses.Cols(ew.cols...)
			}

			if err := ew.engine.Where(ew.condition).Limit(int(int64Size), int(offset)).Find(&beanList); err == nil {
				result.Content = &beanList
				result.CurrentElement = int64(len(beanList))
				return result, nil
			} else {
				return nil, err
			}
		}

	} else {
		return nil, err
	}
}
